#include "ffmsg_queue.h"

void msg_free_obj(AVMessage *msg)
{
    // 空指针校验
    if(!msg || !msg->obj)
        return ;
    // 释放obj资源
    msg->free_l(msg->obj);
    // 更新为NULL，防止野指针
    msg->obj = NULL;
}

int msg_queue_put_private(MessageQueue *q, AVMessage *msg)
{
    // 该方法不用加互斥锁是因为调用它的地方都需要加上互斥锁——即同步

    // 在消息队列中创建一个新的对象
    AVMessage *msg1;
    // 判断中止状态
    if(q->abort_request)
        return -1;
    // 分配内存—— 当前版本未使用回收消息，后续加入
    msg1 = (AVMessage*)av_malloc(sizeof(AVMessage));
    if(!msg1)
        return -1;
    // 赋值
    *msg1 = *msg;
    // 判断队列中是否一个元素都没有，如果没有，那么插入到队列中，即当前是第一个元素
    if(!q->first_msg)
        q->first_msg = msg1;
    // 否则插入到末尾
    else
        q->last_msg->next = msg1;
    // 更新队列中的最后一个元素的指向
    q->last_msg = msg1;
    // 队列中消息数+1
    q->nb_msg++;
    // 通知其他线程中的条件变量，可以获取到消息了
    SDL_CondSignal(q->cond);
    // 返回成功结果
    return 0;
}

int msg_queue_put(MessageQueue *q, AVMessage *msg)
{
    int ret;
    // 加锁
    SDL_LockMutex(q->mutex);
    // 调用真正插入消息的方法
    ret = msg_queue_put_private(q, msg);
    // 释放锁
    SDL_UnlockMutex(q->mutex);
    return ret;
}

void msg_init_msg(AVMessage *msg)
{
    // 清空对象中的参数，全部置为0/变量初始值
    memset(msg, 0, sizeof(AVMessage));
}

void msg_queue_put_simple1(MessageQueue *q, int type)
{
    // 创建消息对象
    AVMessage msg;
    // 初始化消息
    msg_init_msg(&msg);
    msg.type = type;
    // 将消息插入队列中
    msg_queue_put(q, &msg);
}

void msg_queue_put_simple2(MessageQueue *q, int type, int arg1)
{
    // 创建消息对象
    AVMessage msg;
    // 初始化消息
    msg_init_msg(&msg);
    msg.type = type;
    msg.arg1 = arg1;
    // 将消息插入队列中
    msg_queue_put(q, &msg);
}

void msg_queue_put_simple3(MessageQueue *q, int type, int arg1, int arg2)
{
    // 创建消息对象
    AVMessage msg;
    // 初始化消息
    msg_init_msg(&msg);
    msg.type = type;
    msg.arg1 = arg1;
    msg.arg1 = arg2;
    // 将消息插入队列中
    msg_queue_put(q, &msg);
}

void msg_obj_free_l(void *obj)
{
    av_free(obj);
}

void msg_queue_put_simple4(MessageQueue *q, int type, int arg1, int arg2, void *obj, int obj_len, void (*free_l)(void *obj))
{
    // 创建消息对象
    AVMessage msg;
    // 初始化消息
    msg_init_msg(&msg);
    msg.type = type;
    msg.arg1 = arg1;
    msg.arg1 = arg2;
    msg.obj = av_malloc(obj_len);
    memcpy(msg.obj, obj, obj_len);
    msg.free_l = free_l;
    // 将消息插入队列中
    msg_queue_put(q, &msg);
}

void msg_queue_init(MessageQueue *q)
{
    // 初始化数据
    memset(q, 0, sizeof(MessageQueue));
    q->mutex = SDL_CreateMutex();
    q->cond = SDL_CreateCond();
    q->abort_request = 1;//默认停止状态，等待strat启动
}

void msg_queue_flush(MessageQueue *q)
{
    // 加锁
    SDL_LockMutex(q->mutex);
    // 存储下一个结点信息
    AVMessage *next_msg;
    // 遍历当前链表中的每一个结点
    for(AVMessage *msg = q->first_msg; msg != NULL; msg = next_msg)
    {
        // 存储一个结点信息
        next_msg = msg->next;
        // 删除当前结点
        av_free(&msg);
    }
    // 更新队列参数
    q->first_msg = NULL;
    q->last_msg = NULL;
    q->nb_msg = 0;
    // 释放锁
    SDL_UnlockMutex(q->mutex);
}

void msg_queue_destroy(MessageQueue *q)
{
    // 释放队列中的消息对象
    msg_queue_flush(q);

    // 目前未做回收消息重利用机制，故不需要删除回收消息

    // 释放同步对象
    SDL_DestroyMutex(q->mutex);
    SDL_DestroyCond(q->cond);
}

void msg_queue_abort(MessageQueue *q)
{
    // 加锁
    SDL_LockMutex(q->mutex);
    // 设置队列终止状态
    q->abort_request = 1;
    // 通知其他线程
    SDL_CondSignal(q->cond);
    // 释放锁
    SDL_UnlockMutex(q->mutex);
}

void msg_queue_start(MessageQueue *q)
{
    // 加锁
    SDL_LockMutex(q->mutex);
    // 设置队列取消终止状态——即启动
    q->abort_request = 0;
    // 队列中发送一条消息，通知队列删除上一次启动中剩余的消息
    msg_queue_put_simple1(q, FFP_MSG_FLUSH);
    // 释放锁
    SDL_UnlockMutex(q->mutex);
}

int msg_queue_get(MessageQueue *q, AVMessage *msg, int block)
{
    // 加锁
    SDL_LockMutex(q->mutex);
    // 方法结果
    int ret = 0;
    // 队列中的消息
    AVMessage *q_msg;
    while(1)
    {
        // 如果队列已经停止了，那么结束循环等待
        if(q->abort_request)
        {
            ret = -1;
            break;
        }
        // 获取队列中的第一个元素
        q_msg = q->first_msg;
        // 如果队列中有元素
        if(q_msg)
        {
            // 更新队列的第一个元素指向
            q->first_msg = q_msg->next;
            //删除该消息的指向，防止外面使用到该msg的指向来操作到消息队列中的其他消息了
            q_msg->next = NULL;
            // 如果此时队列中没有元素了，那么更新 last_msg 的指向
            if(!q->first_msg)
                q->last_msg = NULL;
            // 队列中消息数量-1
            q->nb_msg--;
            // 将队列中的消息内容赋值给 msg
            *msg = *q_msg;
            // 修改q_msg的obj指向，防止清空时将obj给清空了，因为外面的msg还需要使用obj，故这里清空不能清空外面还能使用到的数据
            q_msg->obj = NULL;
            // 释放q_msg对象
            av_free(q_msg);
            // 标记成功获取到一条数据
            ret = 1;
            break;
        }
        // 如果是非阻塞式，那么在未获取到消息时直接返回结果
        else if(!block)
        {
            ret = 0;
            break;
        // 如果是阻塞式，那么等待队列中获取到消息
        } else {
            // 释放锁，并线程等待通知
            SDL_CondWait(q->cond, q->mutex);
        }
    }
    // 释放锁
    SDL_UnlockMutex(q->mutex);
    // 返回结果
    return ret;
}

void msg_queue_remove(MessageQueue *q, int type)
{
    // 加锁
    SDL_LockMutex(q->mutex);
    // 如果队列已经终止了，则不进行任何操作
    if(q->abort_request)
        return ;
    // 如果队列中存在消息，那么才能删除
    if(q->first_msg)
    {
        // msg指向队列中的每一条消息，防止找不到当前是队列中的哪个消息
        // now_msg指向每次处理的消息
        AVMessage *msg, *now_msg;
        // 指向队列的第一个消息
        msg = q->first_msg;
        // 遍历队列中的每一条消息
        while(!msg)
        {
            // 复制本条消息
            now_msg = msg;
            // 如果本条消息类型匹配成功，那么删除该消息
            if(now_msg->type == type)
            {
                // todo
            }
            // 否则遍历下一条消息
            else
            {
                msg = msg->next;
            }
        }
    }
    // 释放锁
    SDL_UnlockMutex(q->mutex);
}
